package com.pet_service.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Date;
import java.util.Map;

/**
 * JWT工具类
 */
public class JwtUtil {

    /**
     * 默认过期时间 24小时(毫秒)
     */
    private static final long DEFAULT_EXPIRE_TIME = 24 * 60 * 60 * 1000L;

    /**
     * 生成JWT Token
     *
     * @param secret    密钥
     * @param issuer    签发者
     * @param subject   主题
     * @param claims    自定义声明
     * @return JWT Token
     */
    public static String generateToken(String secret, String issuer, String subject, Map<String, String> claims) {
        return generateToken(secret, issuer, subject, claims, DEFAULT_EXPIRE_TIME);
    }

    /**
     * 生成JWT Token
     *
     * @param secret     密钥
     * @param issuer     签发者
     * @param subject    主题
     * @param claims     自定义声明
     * @param expireTime 过期时间(毫秒)
     * @return JWT Token
     */
    public static String generateToken(String secret, String issuer, String subject,
                                       Map<String, String> claims, long expireTime) {
        Algorithm algorithm = Algorithm.HMAC256(secret);
        Date now = new Date();
        Date expiresAt = new Date(now.getTime() + expireTime);

        com.auth0.jwt.JWTCreator.Builder builder = JWT.create()
                .withIssuer(issuer)
                .withSubject(subject)
                .withIssuedAt(now)
                .withExpiresAt(expiresAt);

        // 添加自定义声明
        if (claims != null && !claims.isEmpty()) {
            claims.forEach(builder::withClaim);
        }

        return builder.sign(algorithm);
    }

    /**
     * 验证JWT Token
     *
     * @param token  JWT Token
     * @param secret 密钥
     * @param issuer 签发者
     * @return DecodedJWT对象
     * @throws JWTVerificationException 验证失败异常
     */
    public static DecodedJWT verifyToken(String token, String secret, String issuer)
            throws JWTVerificationException {
        Algorithm algorithm = Algorithm.HMAC256(secret);
        JWTVerifier verifier = JWT.require(algorithm)
                .withIssuer(issuer)
                .build();
        return verifier.verify(token);
    }

    /**
     * 解码JWT Token(不验证签名)
     *
     * @param token JWT Token
     * @return DecodedJWT对象
     */
    public static DecodedJWT decodeToken(String token) {
        return JWT.decode(token);
    }

    /**
     * 获取声明值
     *
     * @param token     JWT Token
     * @param secret    密钥
     * @param issuer    签发者
     * @param claimName 声明名称
     * @return 声明值
     */
    public static Claim getClaim(String token, String secret, String issuer, String claimName) {
        try {
            DecodedJWT jwt = verifyToken(token, secret, issuer);
            return jwt.getClaim(claimName);
        } catch (JWTVerificationException e) {
            return null;
        }
    }

    /**
     * 获取声明值为字符串
     *
     * @param token     JWT Token
     * @param secret    密钥
     * @param issuer    签发者
     * @param claimName 声明名称
     * @return 字符串声明值
     */
    public static String getClaimAsString(String token, String secret, String issuer, String claimName) {
        Claim claim = getClaim(token, secret, issuer, claimName);
        return claim != null ? claim.asString() : null;
    }

    /**
     * 检查Token是否过期
     *
     * @param token  JWT Token
     * @param secret 密钥
     * @param issuer 签发者
     * @return 是否过期
     */
    public static boolean isTokenExpired(String token, String secret, String issuer) {
        try {
            DecodedJWT jwt = verifyToken(token, secret, issuer);
            return jwt.getExpiresAt().before(new Date());
        } catch (JWTVerificationException e) {
            return true;
        }
    }

    /**
     * 刷新Token
     *
     * @param oldToken   原始Token
     * @param secret     密钥
     * @param issuer     签发者
     * @param expireTime 新的过期时间(毫秒)
     * @return 新的Token
     */
    public static String refreshToken(String oldToken, String secret, String issuer, long expireTime) {
        try {
            DecodedJWT jwt = verifyToken(oldToken, secret, issuer);

            // 获取原始声明
            Map<String, Claim> claims = jwt.getClaims();
            new java.util.HashMap<String, String>();
            claims.forEach((key, value) -> {
                if (!"exp".equals(key) && !"iat".equals(key)) {
                    // 注意：这里简化处理，实际可能需要根据具体类型转换
                }
            });

            // 重新生成Token
            return generateToken(secret, issuer, jwt.getSubject(), null, expireTime);
        } catch (JWTVerificationException e) {
            throw new RuntimeException("Token刷新失败", e);
        }
    }
}
